/*! ============================================================================
 * @file oop.c 
 * @Synopsis  
 * @author DongKai
 * @version 1.0
 * @date 2009年12月01日
 *  Company: Beijing Feynman Software Technology Co., Ltd.
 */

#include <stdio.h>
#include <stdlib.h>

typedef union
{
    void *dummpy;
    void (*func_vi)(int);
    void (*func_vv)(void);
    int  (*func_iv)(void);
    int  (*func_ii)(int);
    void  (*func_ip)(void *);
} VirtualFuncsEntry;

typedef struct Vtable
{
    struct Vtable * base;
    VirtualFuncsEntry *entry;
} Vtable;

#define CLASS(type) \
    extern VirtualFuncsEntry type##VtableEntry[]; \
    extern Vtable type##Vtable; \
    typedef struct type

#define FUNCTION_0(retype, funcname) \
    retype (*funcname)()

#define FUNCTION_1(retype, funcname, param1) \
    retype (*funcname)(param1)

CLASS (Object)
{
    union {
        VirtualFuncsEntry *vtable_t;
        void *this_;
    };
    void (*func_vv)(void);
    char * name;
#define ShowName() vtable_t[0].func_ip(gp.g_this)
    FUNCTION_0(void, func);
}Object;

CLASS (Son)
{
    union{
        VirtualFuncsEntry *vtable_t;
        Object base;
        void *this_;
    };
//    void (*func_vi)(int);
    char *name;
    int  id;
}Son;

#define OBJECT(p) ((Object *)p)

union
{
    void * g_this;
    Object * g_object;
    Son * g_son;
}gp;

//#define CAST(typename, obj) ((typename##*)obj)

void PrintName_Object(Object *_this)
{
    printf("My name is %s.\n", _this->name);
}

void PrintName_Son(Son *_this)
{
    printf("My name is %s.\n", _this->name);
}

int PrintId()
{
    printf("My id is %d.\n", gp.g_son->id);
    return 0;
}

int SetId(int ID)
{
    gp.g_son->id = ID;
    printf("Change id to %d.\n", gp.g_son->id);
    return 0;
}

VirtualFuncsEntry ObjectVtableEntry[] = {
    (void *)PrintName_Object,
};
Vtable ObjectVtable = {NULL, ObjectVtableEntry};

VirtualFuncsEntry SonVtableEntry[] = {
    (void *)PrintName_Son,
    (void *)PrintId,
    (void *)SetId
};
Vtable SonVtable = {&ObjectVtable, SonVtableEntry};

void * Route(int index, ...)
{

    return NULL;
}

int ObjectInit(Object *obj)
{
    if (NULL != obj)
    { 
        obj->name = "Object";
        obj->vtable_t = ObjectVtableEntry;
        return 0;
    }
    return -1;
}

Object * ObjectNew()
{
    Object * obj = (Object *)malloc(sizeof(Object));
    ObjectInit(obj);
    return obj;
}

int SonInit(Son * son)
{
    if (NULL != son)
    {
        ObjectInit(OBJECT(son));
        son->name = "Son";
//        son->func_vi = PrintId;
        son->id = 0;
        OBJECT(son)->vtable_t = SonVtableEntry;
        return 0;
    }
    return -1;
}
Son * SonNew()
{
    Son * obj = (Son *)malloc(sizeof(Son));
    SonInit(obj);
    return obj;
}
#define REF(obj) ((gp.g_this = obj), (obj)) 

#define print_name() func_vi(1)//selec_p0(0) 

// ============================================================================
typedef union
{
    void *dummpy;
    void (*func_vi)(int);
    void (*func_vv)(void);
    int  (*func_iv)(void);
    int  (*func_ii)(int);
    int  (*func_ip)(void *);
    void  (*func_vpi)(void *, int);
} vfunc_types;

typedef struct _virtual_function_t {
    const char * __name;
    void *  __address;
} virtual_function_t;

typedef struct _vtable
{
    struct _vtable * __base;
    virtual_function_t * __entry;
} vtable_t;

#define CLASS(type) \
    extern virtual_function_t g_##type##_virtual_functions[]; \
    extern vtable_t g_##type##_vtable; \
    typedef struct type

#define SUB_CLASS_DEFINE(type, base) \
    CLASS(type) { \
    base _super;
#define SUB_CLASS_DEFEND(type) }type;

vtable_t _NOSUPER_vtable = {NULL, NULL};

#define VIRTUAL_MEMFUNC_DEC(type, base) \
    vtable_t g_##type##_vtable = {&g_##base##_vtable, g_##type##_virtual_functions}; \
virtual_function_t g_##type##_virtual_functions[] = { \
    {"constructor", type##constructor}, \
    {"destructor", type##destructor}, \
    {"array_constructor", type##array_constructor}, \
    {"array_destructor", type##array_destructor}, \
    {"print", type##_print}, 

#define VIRTUAL_MEMFUNC(type, funcname) {#funcname, (void *)type##_##funcname},

#define VIRTUAL_MEMFUNC_DECEND {NULL, NULL}};

#define MEMBER_FUNC_DEFINE(type, funcname) type##_##funcname

#define CONSTRUCTOR_DEF(type) \
type * type##constructor(type *, void *); \
    type * type##preconstructor(type * self, void *data) { \
        vtable_t * prev = g_##type##_vtable.__base; \
        *(vtable_t **)self = &g_##type##_vtable; \
        while (prev->__entry) { \
            ((void* (*)(void*, void*))(prev->__entry[0].__address))(self, data); \
            prev = prev->__base; \
        printf("prev= %p\n", prev); \
        } \
        printf("this=%p, %p, %p, %p, %p\n", ((vtable_t *)self), &g_##type##_vtable, &(*(vtable_t **)self)->__base, *(vtable_t **)self, (*(vtable_t **)self)->__base); \
        return type##constructor(self, data); \
    } \
        type * type##array_constructor(type *self, void *data, int num) { \
            type * head = self; \
            int  i = num; \
            while (i--) { \
                type##preconstructor(head++, data); \
            } \
            return self; \
        } \
type * type##constructor(type * self, void *data)

#define DESTRUCTOR_DEFINE(type) \
    void type##destructor(type *); \
    void type##predestructor(type *self) { \
        vtable_t * prev = /* (*(vtable_t **)self); *//* equal to */g_##type##_vtable.__base; \
        type##destructor(self); \
        while (prev->__entry /* && prev->__entry*/) { \
            printf("prev->__entry=%p\n", prev->__entry); \
            ((void (*)(void*))(prev->__entry[1].__address))(self); \
            prev = prev->__base; \
        } \
    } \
void type##array_destructor(type *self, int num) { \
    type * head = self; \
    int  i = num; \
    while (i--) { \
        type##predestructor(head++); \
    } \
    free(self); \
} \
void type##destructor(type * self)

#define NEW(type) type##preconstructor(malloc(sizeof(type)), NULL)
#define NEW_ARGS(type, data) type##preconstructor(malloc(sizeof(type)), data)
#define NEW_ARRAY(type, num) type##array_constructor(malloc(sizeof(type) * num), NULL, num)
#define NEW_ARRAY_ARGS(type, num, data) type##array_constructor(malloc(sizeof(type) * num), data, num)

//#define DELETE(ptr) ((void (*)(void*))(((mybase *)ptr)->vptr->__entry[1].__address))(ptr)
#define DELETE(ptr) ((void (*)(void*, int))((*(vtable_t **)ptr)->__entry[3].__address))(ptr, 1)//((void (*)(void*))((*(vtable_t **)ptr)->__entry[1].__address))(ptr)
#define DELETE_ARRAY(ptr, num) ((void (*)(void*, int))((*(vtable_t **)ptr)->__entry[3].__address))(ptr, num)

#define TEST(ptr) ((void (*)(void))((*(vtable_t **)ptr)->__entry[4].__address))()
CLASS(mybase)
{
    vtable_t * vptr;
    int m;
}mybase;

void MEMBER_FUNC_DEFINE(mybase, print)(void)
{
    puts("base:print");
}

void MEMBER_FUNC_DEFINE(sub1, print)(void)
{
    puts("sub1:print");
}

void MEMBER_FUNC_DEFINE(sub2, print)(void)
{
    puts("sub2:print");
}
CONSTRUCTOR_DEF(mybase)
{
    printf("mybase new %p.\n", self);
    return self;
}

DESTRUCTOR_DEFINE(mybase)
{
    printf("mybase delete %p.\n", self);
}

VIRTUAL_MEMFUNC_DEC(mybase, NOSUPER)
VIRTUAL_MEMFUNC(mybase, print)
VIRTUAL_MEMFUNC_DECEND

SUB_CLASS_DEFINE(sub1, mybase)
    int m;
    SUB_CLASS_DEFEND(sub1);

CONSTRUCTOR_DEF(sub1)
{
    printf("sub1 new %p.\n", self);
    return self;
}
DESTRUCTOR_DEFINE(sub1)
{
    printf("sub1 delete %p.\n", self);
}
VIRTUAL_MEMFUNC_DEC(sub1, mybase)
VIRTUAL_MEMFUNC(sub1, print)
VIRTUAL_MEMFUNC_DECEND


SUB_CLASS_DEFINE(sub2, sub1)
    int m;
    SUB_CLASS_DEFEND(sub2);

CONSTRUCTOR_DEF(sub2)
{
    printf("sub2 new %p.\n", self);
    return self;
}
DESTRUCTOR_DEFINE(sub2)
{
    printf("sub2 delete %p.\n", self);
}
VIRTUAL_MEMFUNC_DEC(sub2, sub1)
VIRTUAL_MEMFUNC_DECEND

void dump_obj(void *obj)
{
    vtable_t *prev = (*(vtable_t **)obj);
    printf("obj ptr = %p\n", obj);
    while (prev->__entry) {
        printf("base = %p.entry = %p.\n", &prev->__base, prev->__entry);
        prev = prev->__base;
    }
}

int main()
{
    printf("_mybase_vtable=%p.\t_mybase_vfuncs=%p.\n", &_mybase_vtable, _mybase_vfuncs);
    printf("_sub1_vtable=%p.\t_sub1_vfuncs=%p.\n", &_sub1_vtable, _sub1_vfuncs);
    printf("_sub2_vtable=%p.\t_sub2_vfuncs=%p.\n", &_sub2_vtable, _sub2_vfuncs);
//    mybase *p = NEW_ARRAY(mybase, 5);
//    DELETE_ARRAY(p, 5);
//    sub1 *s = NEW(sub1);
//    DELETE(s);
    sub2 *ss = NEW(sub2);
    dump_obj(ss);
    TEST(ss);
    printf("guse=%p\n", (*(vtable_t **)ss));
    DELETE(ss);
    return 0;
}
